
using UnityEngine;
using System;
using System.Collections.Generic;


#if UNITY_EDITOR
using UnityEditor;
using System.Reflection;
#endif

/// <summary>
/// 组件绑定工具类
/// 说明：
/// 0. 使用：点击组件菜单栏（三个点）->点击CommonBind
/// 1. 该类提供了一个默认的批量绑定方法，会自动查找所有公共实例字段并绑定对应类型的组件。
/// 2. 子类可以重写AutoBindFieldComponent类中的 Bind 方法来自定义绑定逻辑。
/// 3. 要求：下级节点存在与字段名一致的物体，并且挂载了对应组件
/// </summary>
public static class ExtentiobTool
{
#if UNITY_EDITOR
    [MenuItem("CONTEXT/MonoBehaviour/CommonBind")]
    public static void Bind(MenuCommand command)
    {
        // 获取选中的 MonoBehaviour 组件
        MonoBehaviour monoBehaviour = (MonoBehaviour)command.context;

        if (monoBehaviour != null)
        {
            if (monoBehaviour is AutoBindFieldComponent autoBindFieldComponent)
            {
                autoBindFieldComponent.Bind();
            }
            else
            {
                AutoBindFieldComponent.Bind(monoBehaviour);
            }
            // 及时保存预制体
            AssetDatabase.SaveAssets();
        }
    }
#endif
}
/// <summary>
/// 子类可以重写AutoBindFieldComponent类中的 Bind 方法来自定义绑定逻辑。
/// </summary>
public class AutoBindFieldComponent : MonoBehaviour
{

#if UNITY_EDITOR
    public static void Bind(MonoBehaviour mono)
    {
        try
        {
            // 获取当前类的所有公共实例字段
            FieldInfo[] fields = mono.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                // 确保字段类型是 Component 或其子类
                if (typeof(UnityEngine.Component).IsAssignableFrom(field.FieldType))
                {

                    // 获取字段的值
                    var targetFieldValue = FindFieldValue(mono, field.Name, field.FieldType);
                    // 将绑定后的结果赋值回字段
                    if (targetFieldValue == null)
                    {
                        Debug.LogError($"class:{mono.GetType().Name},fieldName:{field.Name}\nBind property failed! Child object '{field.Name}' not found.");
                        continue;
                    }
                    // 将绑定后的结果赋值回字段
                    field.SetValue(mono, targetFieldValue);
                }
                else if (field.FieldType == typeof(GameObject))
                {//field 是gameobject
                    var findTrans = FindChildByName(mono.transform, field.Name);
                    if (findTrans)
                    {
                        var value = findTrans.gameObject;
                        if (value == null)
                        {
                            Debug.LogError($"class:{mono.GetType().Name},fieldName:{field.Name}\nBind property failed! Child object '{field.Name}' not found.");
                            continue;
                        }
                        field.SetValue(mono, value);
                    }
                }
                else
                {

                }
            }

        }
        catch (System.Exception ex)
        {
            UnityEngine.Debug.LogError($"批量绑定出错: {ex.Message}");
        }
        EditorUtility.SetDirty(mono);
    }

    /// <summary>
    /// 通过字段名查找子对象并绑定对应类型的组件
    /// </summary>
    /// <typeparam name="T">要绑定的组件类型</typeparam>
    /// <param name="obj">用于存储绑定结果的引用</param>
    /// <param name="fieldName">字段名</param>
    protected static UnityEngine.Object FindFieldValue(Component obj, string fieldName, Type fieldType)
    {
        try
        {
            //找到子集中和字段同名的物体
            var trans = FindChildByName(obj.transform, fieldName);
            if (trans == null)
            {
                Debug.LogError($"class:{obj.GetType().Name},fieldName:{fieldName}\nBind property failed! Child object '{fieldName}' not found.");
                return null;
            }
            var targetFieldValue = trans.GetComponent(fieldType);
            if (targetFieldValue == null)
            {
                Debug.LogError($"class:{targetFieldValue.GetType().Name},fieldName:{fieldName}\nBind property failed! Component of type '{fieldType.Name}' not found on child object '{fieldName}'.");
                return null;
            }
            Debug.Log("Bind property succ! name:" + fieldName + ",type:" + fieldType.Name);
            return targetFieldValue;
        }
        catch (System.Exception e)
        {
            Debug.LogError($"class:{obj.GetType().Name},fieldName:{fieldName}\nBind property failed! name:" + fieldName + ",error:" + e);
            return null;
        }
    }
#endif
    /// <summary>
    /// 默认批量绑定所有组件
    /// </summary>
    public virtual void Bind()
    {
#if UNITY_EDITOR
        Bind(this);
#endif
    }
    protected void SetDiaty(UnityEngine.Object obj)
    {
#if UNITY_EDITOR
        EditorUtility.SetDirty(obj);
#endif
    }
    /// <summary>
    /// 递归查找到对应名字的节点
    /// </summary>
    /// <param name="parent">根路径</param>
    /// <param name="name"></param>
    /// <returns></returns>
    protected static Transform FindChildByName(Transform parent, string name)
    {
        if (parent.name == name)
        {
            return parent;
        }
        foreach (Transform child in parent)
        {
            if (child.name == name)
                return child;

            Transform found = FindChildByName(child, name);
            if (found != null)
                return found;
        }
        return null;
    }
    public event Action TestAction;
    protected virtual void Update()
    {
#if UNITY_EDITOR
        if (Input.GetKeyDown(KeyCode.Space))
        {
            TestAction?.Invoke();
        }
#endif
    }
    public virtual List<ActionItem> GetActions()
    {
        return new List<ActionItem>();
    }
}
public struct ActionItem
{
    public Action TestAction;
    public string actionKey;
}
#if UNITY_EDITOR
[CustomEditor(typeof(AutoBindFieldComponent), true)] // 注意这里的 true 参数很重要
[CanEditMultipleObjects]
public class AutoBindFieldComponentEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        var component = target as AutoBindFieldComponent;
        var actions = component.GetActions();
        foreach (var item in actions)
        {
            if (GUILayout.Button(item.actionKey))
            {
                item.TestAction?.Invoke();
            }
        }
    }
}
#endif
